﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.ComponentModel;
using System.Text;
using System.Drawing;
using Asol.Reporting.Editor.Editor;
using Asol.Reporting.Editor.Components;
using System.Windows.Forms;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using Asol.Reporting.Editor.ComponentsLayer;
using Asol.Reporting.Editor.Data;
using Asol.Reporting.Support;
using Asol.Reporting.Editor.Pics;

namespace Asol.Reporting.Editor.ReportObjects
{
    #region abstract class ReportObject : nepovinná bázová třída pro prvky reportu. Sama kompletně implementuje IReportObject a převádí jej na protected virtual members.
    /// <summary>
    /// ReportObject : dobrovolná bázová třída pro konkrétní typy objektů reportu.
    /// Implementuje IReportObject, jehož members převádí na protected virtual members.
    /// </summary>
    public abstract class ReportObject : IReportObject
    {
        #region Konstrukce
        /// <summary>
        /// Konstruktor
        /// </summary>
        public ReportObject()
        {
            this.EnableMultiBand = false;
            this.InteractivityMode = EditItemInteractivityMode.All;
        }
        #endregion
        #region Vlastnosti v Menu + Toolbaru (UI)
        /// <summary>
        /// Property, která obsahuje veškeré informace pro tvorbu UI
        /// </summary>
        protected abstract MenuItemInfo MenuInfo { get; }
        #endregion
        #region Public property viditelné v PropertyGridu
        /// <summary>
        /// Jméno prvku. Slouží k identifikaci prvku v seznamu.
        /// </summary>
        [Browsable(true)]
        [Description("Jméno prvku. Slouží k identifikaci prvku v seznamu.")]
        [Category("General")]
        public string Name { get; set; }
        #endregion
        #region Protected virtual property a metody, fyzická implementace property předepsaných v interface
        /// <summary>
        /// Majitel tohoto objektu = objekt ReportComponent, který zprostředkovává vazby na dokument, editor, záhlaví a další.
        /// </summary>
        protected virtual ReportComponent Owner
        {
            get { return this._Owner; }
            set
            {
                this._Owner = value;
                if (value != null && String.IsNullOrEmpty(this.Name))
                    this.CreateName();
            }
        }
        /// <summary>
        /// Majitel tohoto objektu = komponenta reportu (podvozek, na kterém tento objekt jezdí)
        /// </summary>
        protected ReportComponent _Owner;
        /// <summary>
        /// Výchozí jméno objektu, k němuž se přidává pořadové číslo _1 až _999.
        /// Třída ReportObject v této virtual property generuje jméno výchozí = jméno třídy, z něhož odstraní text "ReportObject".
        /// </summary>
        [Browsable(false)]
        protected virtual string ImplicitName
        {
            get
            {
                string name = this.GetType().Name;           // Jméno třídy bez namespace
                name = name.Replace("ReportObject", "");
                return name;
            }
        }
        /// <summary>
        /// Jméno komponenty do nabídky objektů.
        /// Mělo by obsahovat Name + identifikaci zobrazovaných dat, pokud to je možné.
        /// </summary>
        protected virtual string ComponentName { get { return this.Name; } }
        /// <summary>
        /// Příznak, že tato komponenta může mít rozsah přes více Bands. Default = false.
        /// Povolit na true je vhodné pouze u těch komponent, které to dokážou vykreslit. Typicky jde o rámečky, linky atd.
        /// Nevhodné je to pro texty, obrázky atd.
        /// </summary>
        protected virtual bool EnableMultiBand { get; set; }
        /// <summary>
        /// Property udává možnosti interaktivity tohoto prvku.
        /// Na základě hodnoty v této property pak prvek deklaruje aktivní segmenty a jejich vlastnosti, 
        /// viz metoda this.PrepareSegments().
        /// Bázová třída obsahuje hodnotu StandardActiveResize, 
        /// potomek ji může předefinovat (property je virtual), a bázová třída pak v metodě PrepareSegments() deklaruje odpovídající segmenty.
        /// </summary>
        protected virtual EditItemInteractivityMode InteractivityMode { get; set; }
        /// <summary>
        /// Aktuální vizuální souřadnice na ploše editoru.
        /// Jsou nastaveny před kreslením, pokud dochází k jejich změně.
        /// Na změny souřadnice prvek nemá reagovat voláním ReDraw(), to by mohlo vést ke zpomalení nebo zacyklení editoru.
        /// Prvek sám by je neměl měnit, nedává to smysl.
        /// Jsou zde uloženy pro interní potřeby tohoto prvku.
        /// </summary>
        protected virtual RectangleF EditorVisualBounds { get; set; }
        /// <summary>
        /// Zámek editace pozice objektu.
        /// Editor (uživatel) může některé objekty zamknout, pak se tyto objekty nepohybují ani neresizují, a to ani při hromadných změnách.
        /// Prvek na to reaguje vizuálně: nezobrazuje odpovídající úchyty (Segmenty), nepodporuje přesouvání (Body).
        /// </summary>
        protected virtual bool EditorLocked { get; set; }
        /// <summary>
        /// Aktivita třídy z pohledu běhu v Debug režimu (programátorský)
        /// </summary>
        protected virtual PluginActivityMode PluginActivity { get { return PluginActivityMode.Standard; } }
        /// <summary>
        /// Licenční kód, který povoluje použití komponenty.
        /// Jde o textový souhrn kódů konfigurace modulů.
        /// </summary>
        protected virtual string LicenseCode { get { return null; } }
        #endregion
        #region Příprava interaktivních segmentů, testy vlastní interaktivity, háček interaktivity
        /// <summary>
        /// Voláno v době editace.
        /// Umožní prvku, aby korigoval souřadnice a/nebo velikost prvku.
        /// </summary>
        /// <param name="args"></param>
        protected virtual void EditorLogicalBoundsChange(ReportObjectLogicalBoundsChangeArgs args) { }
        /// <summary>
        /// Voláno v době editace.
        /// Připraví a do argumentu args vloží soupis svých segmentů, které chce v dané chvíli zobrazit.
        /// V argumentu dostává informace o prostoru prvku a jeho stavu, do argumentu přidává jednotlivé segmenty.
        /// </summary>
        /// <param name="args"></param>
        protected virtual void PrepareInteractiveSegments(ReportObjectPrepareSegmentsArgs args)
        {
            this.Owner.CreateStandardSegments(args, this.EditorLocked, this.InteractivityMode);

            switch (args.ObjectState)
            {
                case EditorObjectState.Select:
                    this.PrepareInteractiveSegmentsSelect(args);
                    break;
                case EditorObjectState.Anchor:
                    this.PrepareInteractiveSegmentsAnchor(args);
                    break;
            }
        }
        /// <summary>
        /// Voláno v době editace.
        /// Připraví a do argumentu args vloží soupis svých segmentů, které chce v dané chvíli zobrazit v režimu Select
        /// V argumentu dostává informace o prostoru prvku a jeho stavu, do argumentu přidává jednotlivé segmenty.
        /// </summary>
        /// <param name="args"></param>
        protected virtual void PrepareInteractiveSegmentsSelect(ReportObjectPrepareSegmentsArgs args)
        {
        }
        /// <summary>
        /// Voláno v době editace.
        /// Připraví a do argumentu args vloží soupis svých segmentů, které chce v dané chvíli zobrazit v režimu Anchor
        /// V argumentu dostává informace o prostoru prvku a jeho stavu, do argumentu přidává jednotlivé segmenty.
        /// </summary>
        /// <param name="args"></param>
        protected virtual void PrepareInteractiveSegmentsAnchor(ReportObjectPrepareSegmentsArgs args)
        {
        }
        /// <summary>
        /// Voláno v době editace.
        /// Prvek může reagovat na aktuální aktivitu myši.
        /// </summary>
        /// <param name="args"></param>
        protected virtual void EditorSegmentInteractivity(ReportObjectInteractiveSegmentsArgs args) { }
        /// <summary>
        /// Je tento prvek v průběhu editace interaktivní?
        /// true = jeho InteractivityMode obsahuje nahozený některý bit (kterýkoli), false = neobsahuje nic (=None).
        /// </summary>
        protected virtual bool IsInteractive { get { return (this.HasInteractiveModeAny(EditItemInteractivityMode.All)); } }
        /// <summary>
        /// Má tento element povolené všechny dotazované režimy interaktivity?
        /// Pokud jich je zadáno více, musí je mít všechny (jeden ze zadaných nestačí).
        /// Například: pokud testuji režim Resize (což je ResizeX + ResizeY), 
        /// pak vrací true jen tehdy, když současný režim InteractivityMode obsahuje oba bity, tedy jak ResizeX, tak i ResizeY.
        /// Existuje párová metoda, HasInteractiveModeAny, která by vrátila true i jen pro bit ResizeX.
        /// </summary>
        /// <param name="interactivityTest"></param>
        /// <returns></returns>
        protected bool HasInteractiveModeAll(EditItemInteractivityMode interactivityTest)
        {
            int currMode = (int)this.InteractivityMode;
            int testMode = (int)interactivityTest;
            return ((currMode & testMode) == testMode);
        }
        /// <summary>
        /// Má tento element alespoň jeden dotazovaný režim interaktivity?
        /// Pokud jich je zadáno více, stačí jeden z nich..
        /// Například: pokud testuji režim Resize (což je ResizeX + ResizeY), 
        /// pak vrací true pro režimy jak ResizeX, tak i ResizeY, tak i pro Resize.
        /// Existuje párová metoda, HasInteractiveModeAll, která by vrátila true jen pokud by současný režim byl (ResizeX a současně ResizeY).
        /// </summary>
        /// <param name="interactivityTest"></param>
        /// <returns></returns>
        protected bool HasInteractiveModeAny(EditItemInteractivityMode interactivityTest)
        {
            int currMode = (int)this.InteractivityMode;
            int testMode = (int)interactivityTest;
            return ((currMode & testMode) > 0);
        }
        #endregion
        #region Vykreslení prvku v editoru
        /// <summary>
        /// Voláno v době editace.
        /// Prvek kompletně vykreslí sebe (pozadí, popředí), svůj stav Selected, a všechny svoje připravené segmenty.
        /// Bázová metoda třídy ReportObject vyvolá jednotlivé metody kreslení:
        /// pozadí EditorDrawBackground(), rámce EditorDrawFrame(), obsahu EditorDrawContent(), selectu EditorDrawSelect() a segmentů EditorDrawSegments().
        /// </summary>
        /// <param name="args"></param>
        protected virtual void EditorPaint(ReportObjectDrawArgs args)
        {
            this.EditorPaintBackground(args);
            this.EditorPaintFrame(args);
            this.EditorPaintContent(args);
            this.EditorPaintSelect(args);
            this.EditorPaintSegments(args);
        }
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslení pozadí.
        /// Bázová metoda ve třídě ReportObject nekreslí nic (ReportObject nemá ani barvu, ani text).
        /// Pořadí kreslících metod je: pozadí EditorDrawBackground(), rámce EditorDrawFrame(), obsahu EditorDrawContent(), selectu EditorDrawSelect() a segmentů EditorDrawSegments().
        /// </summary>
        /// <param name="args"></param>
        protected virtual void EditorPaintBackground(ReportObjectDrawArgs args)
        { }
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslení tenkého rámu okolo prvku. Rám by měl mít každý prvek, aby byly zřetelné jeho fyzické rozměry.
        /// Rám může potlačit prvek, který kreslí svůj rám jako svůj významný prvek, potlačení se provede overridem této metody bez volání base.
        /// Bázová metoda ve třídě ReportObject nekreslí nic (ReportObject nemá ani barvu, ani text).
        /// Pořadí kreslících metod je: pozadí EditorDrawBackground(), rámce EditorDrawFrame(), obsahu EditorDrawContent(), selectu EditorDrawSelect() a segmentů EditorDrawSegments().
        /// </summary>
        /// <param name="args"></param>
        protected virtual void EditorPaintFrame(ReportObjectDrawArgs args)
        {
            if (!args.Selected)
            {
                using (Pen pen = this.GetPenForFrame(args))
                {
                    Rectangle bound = Rectangle.Round(args.CurrentVisualBound);
                    bound.Width -= 1;
                    bound.Height -= 1;
                    args.Graphics.DrawRectangle(pen, bound);
                }
            }
        }
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslení obsahu.
        /// Bázová metoda ve třídě ReportObject nekreslí nic (ReportObject nemá ani barvu, ani text).
        /// Pořadí kreslících metod je: pozadí EditorDrawBackground(), rámce EditorDrawFrame(), obsahu EditorDrawContent(), selectu EditorDrawSelect() a segmentů EditorDrawSegments().
        /// </summary>
        /// <param name="args"></param>
        protected virtual void EditorPaintContent(ReportObjectDrawArgs args)
        { }
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslení stavu Selected. Metoda je volána vždy, sama si může testovat stav args.Selected.
        /// Bázová metoda ve třídě ReportObject kreslí obyčejný rámeček okolo args.CurrentVisualBound, kreslí perem z metody GetPenForSelection().
        /// Pořadí kreslících metod je: pozadí EditorDrawBackground(), rámce EditorDrawFrame(), obsahu EditorDrawContent(), selectu EditorDrawSelect() a segmentů EditorDrawSegments().
        /// </summary>
        /// <param name="args"></param>
        protected virtual void EditorPaintSelect(ReportObjectDrawArgs args)
        {
            if (args.Selected)
            {
                using (Pen pen = this.GetPenForSelection(args))
                {
                    RectangleF bound = args.CurrentVisualBound;
                    bound.Width -= 1;
                    bound.Height -= 1;
                    args.Graphics.DrawRectangle(pen, Rectangle.Round(bound));
                }
            }
        }
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslení všech segmentů.
        /// Bázová metoda ve třídě ReportObject pro každý segment dle definice (args.Segments) vyvolá metodu EditorDrawSegmentOne().
        /// Pořadí kreslících metod je: pozadí EditorDrawBackground(), rámce EditorDrawFrame(), obsahu EditorDrawContent(), selectu EditorDrawSelect() a segmentů EditorDrawSegments().
        /// </summary>
        /// <param name="args"></param>
        protected virtual void EditorPaintSegments(ReportObjectDrawArgs args)
        {
            foreach (EditorItemSegment segment in args.Segments)
                this.EditorDrawSegmentOne(args, segment);
        }
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslení jednoho každého segmentu.
        /// Bázová metoda ve třídě ReportObject vykreslí pouze standardní segmenty. Pro segmenty typu User převolá metodu EditorDrawSegmentUser().
        /// Pořadí kreslících metod je: pozadí EditorDrawBackground(), rámce EditorDrawFrame(), obsahu EditorDrawContent(), selectu EditorDrawSelect() a segmentů EditorDrawSegments().
        /// </summary>
        /// <param name="args"></param>
        /// <param name="segment"></param>
        protected virtual void EditorDrawSegmentOne(ReportObjectDrawArgs args, EditorItemSegment segment)
        {
            switch (segment.GripType)
            {
                case EditorItemSegmentGripType.None:
                case EditorItemSegmentGripType.Body:
                case EditorItemSegmentGripType.TopCenter:
                case EditorItemSegmentGripType.BottomCenter:
                case EditorItemSegmentGripType.MiddleLeft:
                case EditorItemSegmentGripType.MiddleRight:
                case EditorItemSegmentGripType.TopLeft:
                case EditorItemSegmentGripType.TopRight:
                case EditorItemSegmentGripType.BottomRight:
                case EditorItemSegmentGripType.BottomLeft:
                    this.Owner.DrawStandardSegmentOne(args, segment);
                    break;
                case EditorItemSegmentGripType.UserDefined:
                    this.EditorDrawSegmentUser(args, segment);
                    break;
            }
        }
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslení segmentu typu UserDefined.
        /// Bázová metoda ve třídě ReportObject nevykreslí nic.
        /// Pořadí kreslících metod je: pozadí EditorDrawBackground(), rámce EditorDrawFrame(), obsahu EditorDrawContent(), selectu EditorDrawSelect() a segmentů EditorDrawSegments().
        /// </summary>
        /// <param name="args"></param>
        /// <param name="segment"></param>
        protected virtual void EditorDrawSegmentUser(ReportObjectDrawArgs args, EditorItemSegment segment)
        { }
        /// <summary>
        /// Metoda vrátí nové pero pro kreslení rámečku Frame okolo vybraného prvku (kreslí se tehdy, když prvek není Selectován).
        /// Pozor: pero se použije v using patternu, po použití tedy bude disposováno.
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        protected virtual Pen GetPenForFrame(ReportObjectDrawArgs args)
        {
            Pen pen = new Pen(Color.Gray);
            pen.DashStyle = DashStyle.Dot;
            return pen;
        }
        /// <summary>
        /// Metoda vrátí nové pero pro kreslení rámečku Selection okolo vybraného prvku.
        /// Pozor: pero se použije v using patternu, po použití tedy bude disposováno.
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        protected virtual Pen GetPenForSelection(ReportObjectDrawArgs args)
        {
            return new Pen(Color.LawnGreen, 2f);
        }
        /// <summary>
        /// Metoda vrátí Brush, který se použije pro vykreslení daného segmentu.
        /// Metoda se (v bázové třídě ReportObject) volá pouze pro segmenty TopCenter až BottomLeft (rohy a hrany).
        /// Pozor: štětec se použije v using patternu, po použití tedy bude disposován.
        /// Potomek může reagovat na typ segmentu.
        /// </summary>
        /// <param name="args"></param>
        /// <param name="segment"></param>
        /// <returns></returns>
        protected virtual Brush EditorGetBrushForSegment(ReportObjectDrawArgs args, EditorItemSegment segment)
        {
            return this.Owner.GetBrushForSegment(args, segment);
        }
        #endregion
        #region Různé služby pro potomstvo, protected
        /// <summary>
        /// Metoda vytvoří implicitní jméno pro tento prvek.
        /// Metoda se typicky volá po setování this._Owner, protože teprve poté lze enumerovat komponenty v Owner.Document 
        /// a najít tak první nepoužité jméno.
        /// Metoda využívá property this.ImplicitName.
        /// </summary>
        protected virtual void CreateName()
        {
            if (this._Owner == null || this._Owner.Document == null || this._Owner.Document.Components == null) return;
            
            string implicitName = this.ImplicitName;
            if (String.IsNullOrEmpty(implicitName)) return;
            
            Dictionary<string, object> usedNames = new Dictionary<string, object>();
            foreach (ReportComponent component in this._Owner.Document.Components)
            {
                ReportObject reportObject = component.ReportObject as ReportObject;
                if (reportObject != null)
                {
                    string reportObjectName = reportObject.Name;
                    if (!String.IsNullOrEmpty(reportObjectName) && reportObjectName.StartsWith(implicitName) && !usedNames.ContainsKey(reportObjectName) && !Object.ReferenceEquals(reportObject, this))
                        usedNames.Add(reportObjectName, null);
                }
            }

            int i = 1;
            while (true)
            {
                string name = implicitName + "_" + i.ToString();
                if (!usedNames.ContainsKey(name))
                {
                    this.Name = name;
                    break;
                }
                i++;
            }
        }
        /// <summary>
        /// Metoda vrátí brush pro vykreslení pozadí s danou barvou, v aktuálním stavu myši.
        /// Pokud barva pozadí je prázdná nebo plně průhledná, pak: 
        /// a) pokud stav myši je IsWithMouse pak se použije defaultní barva, 
        /// b) pokud je objekt bez myši, pak se vrací null.
        /// </summary>
        /// <param name="args">Data pro kreslení</param>
        /// <param name="backColor">Nastavená barva pozadí</param>
        /// <param name="renderStyle">Styl renderování v případě args.IsWithMouse, kdy reaguje na stav myši args.MouseState</param>
        /// <param name="interactiveColorShift">Barevný posun pro tvorbu interaktivní barvy</param>
        /// <returns></returns>
        protected virtual Brush EditorGetBackBrush(ReportObjectDrawArgs args, Color backColor, RenderStyle renderStyle, int interactiveColorShift)
        {
            if (args.IsWithMouse)
            {
                LinearGradientBrush lgb = new LinearGradientBrush(args.CurrentVisualBound, backColor, backColor, 90f);
                lgb.InterpolationColors = UiRenderer.GetColorBlend(backColor, interactiveColorShift, renderStyle, args.MouseState);
                return lgb;
            }
            else if (IsColorVisible(backColor))
            {
                Brush brush = new SolidBrush(backColor);
                return brush;
            }
            return null;
        }
        /// <summary>
        /// Vrací pero pro kreslení okrajů.
        /// Pokud je barva pera empty nebo průhledná, nebo daná šířka není kladná, vrací null.
        /// Šířku pera upravuje v měřítku zobrazení.
        /// Lomy hran budou kulaté.
        /// </summary>
        /// <param name="args"></param>
        /// <param name="penColor"></param>
        /// <param name="penWidth"></param>
        /// <returns></returns>
        protected virtual Pen EditorGetPen(ReportObjectDrawArgs args, Color penColor, float penWidth)
        {
            if (!this.IsColorVisible(penColor) || penWidth <= 0f) return null;
            float width = args.ViewPortConvertor.VisualFromLogical(penWidth);
            Pen pen = new Pen(penColor, width);
            pen.LineJoin = LineJoin.Round;
            return pen;
        }
        /// <summary>
        /// Vrací true pokud daná barva je viditelná (true = bude vidět)
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        protected bool IsColorVisible(Color color)
        {
            return (!color.IsEmpty || color.A > 0);
        }
        /// <summary>
        /// Vrátí GraphicsPath odpovídající this objektu v editoru
        /// </summary>
        /// <param name="args"></param>
        /// <param name="shapeArea"></param>
        /// <param name="shapeType"></param>
        /// <param name="penWidth"></param>
        /// <param name="shapeEdge"></param>
        /// <param name="pathType"></param>
        /// <returns></returns>
        protected virtual GraphicsPath CreateEditorGraphicsPath(ReportObjectDrawArgs args, RectangleF shapeArea, ShapeType shapeType, float penWidth, float shapeEdge, GraphicPathType pathType)
        {
            GraphicsPath path = new GraphicsPath();
            RectangleF area = shapeArea;
            float min2 = (area.Width < area.Height ? area.Width : area.Height) / 2f;    // Ten menší z rozměrů (Width, Height), dělený 2
            float borderWidth = args.ViewPortConvertor.VisualFromLogical(penWidth);
            if (borderWidth > min2) borderWidth = min2;                                 // Šířka okraje musí být nejvýše 1/2 rozměru prvku (chráníme se před tlustými okraji)
            if (borderWidth > 0f)
            {   // Objekt umístit dovnitř rámečku shapeArea = tj. zmenšit rámeček o půl-šířku pera:
                float borderHalf = borderWidth / 2f;
                area.X += borderHalf;
                area.Y += borderHalf;
                area.Width -= borderWidth;
                area.Height -= borderWidth;
            }
            min2 = (area.Width < area.Height ? area.Width : area.Height) / 2f;          // Ten menší z rozměrů, dělený 2

            float edge;
            switch (shapeType)
            {
                case ShapeType.Rectangle:
                    path.AddRectangle(area);
                    break;
                case ShapeType.Corners:
                    if (pathType == GraphicPathType.Pen)
                    {
                        edge = args.ViewPortConvertor.VisualFromLogical(shapeEdge); // Míra zkosení v pixelech
                        if (edge > min2) edge = min2;
                        if (edge <= 0f) edge = 0.1f;

                        path.StartFigure();
                        path.AddLine(area.X, area.Y + edge, area.X, area.Y);
                        path.AddLine(area.X, area.Y, area.X + edge, area.Y);

                        path.StartFigure();
                        path.AddLine(area.Right - edge, area.Y, area.Right, area.Y);
                        path.AddLine(area.Right, area.Y, area.Right, area.Y + edge);

                        path.StartFigure();
                        path.AddLine(area.Right, area.Bottom - edge, area.Right, area.Bottom);
                        path.AddLine(area.Right, area.Bottom, area.Right - edge, area.Bottom);

                        path.StartFigure();
                        path.AddLine(area.X + edge, area.Bottom, area.X, area.Bottom);
                        path.AddLine(area.X, area.Bottom, area.X, area.Bottom - edge);
                    }
                    else
                    {
                        path.AddRectangle(area);
                    }
                    break;
                case ShapeType.Ellipse:
                    path.AddEllipse(area);
                    break;
                case ShapeType.RoundEdge:
                    edge = args.ViewPortConvertor.VisualFromLogical(shapeEdge);   // Míra zkosení v pixelech
                    if (edge > min2) edge = min2;
                    float edg2 = 2f * edge;
                    bool hasArc = (edg2 > 0f);
                    path.AddLine(new PointF(area.X + edge, area.Y), new PointF(area.Right - edge, area.Y));
                    if (hasArc)
                        path.AddArc(area.Right - edg2, area.Y, edg2, edg2, 270f, 90f);
                    path.AddLine(new PointF(area.Right, area.Y + edge), new PointF(area.Right, area.Bottom - edge));
                    if (hasArc)
                        path.AddArc(area.Right - edg2, area.Bottom - edg2, edg2, edg2, 0f, 90f);
                    path.AddLine(new PointF(area.Right - edge, area.Bottom), new PointF(area.X + edge, area.Bottom));
                    if (hasArc)
                        path.AddArc(area.X, area.Bottom - edg2, edg2, edg2, 90f, 90f);
                    path.AddLine(new PointF(area.X, area.Bottom - edge), new PointF(area.X, area.Y + edge));
                    if (hasArc)
                        path.AddArc(area.X, area.Y, edg2, edg2, 180f, 90f);
                    path.CloseFigure();
                    break;
                case ShapeType.BevelEdge:
                    edge = args.ViewPortConvertor.VisualFromLogical(shapeEdge);   // Míra zkosení v pixelech
                    if (edge > min2) edge = min2;
                    path.AddLines(new PointF[] {
						new PointF(area.X + edge, area.Y),
						new PointF(area.Right - edge, area.Y),
						new PointF(area.Right, area.Y + edge),
						new PointF(area.Right, area.Bottom - edge),
						new PointF(area.Right - edge, area.Bottom),
						new PointF(area.X + edge, area.Bottom),
						new PointF(area.X, area.Bottom - edge),
						new PointF(area.X, area.Y + edge),
						new PointF(area.X + edge, area.Y)});
                    path.CloseFigure();
                    break;
            }
            return path;
        }
        /// <summary>
        /// Druh generované GraphicsPath.
        /// Pro některé typy ShapeType se liší.
        /// </summary>
        protected enum GraphicPathType
        {
            /// <summary>Pro Background</summary>
            Background,
            /// <summary>Pro Pen</summary>
            Pen
        }
        /// <summary>
        /// Vrátí souřadnice prostoru dané velikosti (size) umístěné do daných souřadnic (bound) podle požadovaného zarovnání (alignment).
        /// </summary>
        /// <param name="bound">Souřadnice prostoru, do něhož se má provést zarovnání objektu</param>
        /// <param name="size">Velikost objektu, který se má umístit</param>
        /// <param name="alignment">Druh zarovnání objektu do přiděleného prostoru</param>
        /// <returns></returns>
        protected virtual RectangleF GetBoundOfSizeAlignedToBound(RectangleF bound, SizeF size, ContentAlignment alignment)
        {
            return this._GetBoundOfSizeAlignedToBound(bound, size, alignment, AlignSizeMode.OriginalSize, false);
        }
        /// <summary>
        /// Vrátí souřadnice prostoru dané velikosti (size) umístěné do daných souřadnic (bound) podle požadovaného zarovnání (alignment).
        /// </summary>
        /// <param name="bound">Souřadnice prostoru, do něhož se má provést zarovnání objektu</param>
        /// <param name="size">Velikost objektu, který se má umístit</param>
        /// <param name="alignment">Druh zarovnání objektu do přiděleného prostoru</param>
        /// <param name="noClipResultToBound">Požadavek, aby výsledný prostor nebyl oříznut do přidělených souřadnic (pokud by objekt byl větší).
        /// false = oříznout (default) /  true = neořezávat</param>
        /// <returns></returns>
        protected virtual RectangleF GetBoundOfSizeAlignedToBound(RectangleF bound, SizeF size, ContentAlignment alignment, bool noClipResultToBound)
        {
            return this._GetBoundOfSizeAlignedToBound(bound, size, alignment, AlignSizeMode.OriginalSize, noClipResultToBound);
        }
        /// <summary>
        /// Vrátí souřadnice prostoru dané velikosti (size) umístěné do daných souřadnic (bound) podle požadovaného zarovnání (alignment).
        /// </summary>
        /// <param name="bound">Souřadnice prostoru, do něhož se má provést zarovnání objektu</param>
        /// <param name="size">Velikost objektu, který se má umístit</param>
        /// <param name="alignment">Druh zarovnání objektu do přiděleného prostoru</param>
        /// <param name="sizeMode">Druh práce s velikostí objektu (možnost změny: zvětšení, zmenšení, zachování ratio), vhodné pro obrázky.</param>
        /// <returns></returns>
        protected RectangleF GetBoundOfSizeAlignedToBound(RectangleF bound, SizeF size, ContentAlignment alignment, AlignSizeMode sizeMode)
        {
            return this._GetBoundOfSizeAlignedToBound(bound, size, alignment, sizeMode, false);
        }
        /// <summary>
        /// Vrátí souřadnice prostoru dané velikosti (size) umístěné do daných souřadnic (bound) podle požadovaného zarovnání (alignment).
        /// </summary>
        /// <param name="bound">Souřadnice prostoru, do něhož se má provést zarovnání objektu</param>
        /// <param name="size">Velikost objektu, který se má umístit</param>
        /// <param name="alignment">Druh zarovnání objektu do přiděleného prostoru</param>
        /// <param name="sizeMode">Druh práce s velikostí objektu (možnost změny: zvětšení, zmenšení, zachování ratio), vhodné pro obrázky.</param>
        /// <param name="noClipResultToBound">Požadavek, aby výsledný prostor nebyl oříznut do přidělených souřadnic (pokud by objekt byl větší).
        /// false = oříznout (default) /  true = neořezávat</param>
        /// <returns></returns>
        protected RectangleF GetBoundOfSizeAlignedToBound(RectangleF bound, SizeF size, ContentAlignment alignment, AlignSizeMode sizeMode, bool noClipResultToBound)
        {
            return this._GetBoundOfSizeAlignedToBound(bound, size, alignment, sizeMode, noClipResultToBound);
        }
        /// <summary>
        /// Vrátí souřadnice prostoru dané velikosti (size) umístěné do daných souřadnic (bound) podle požadovaného zarovnání (alignment).
        /// Privátní výkonná metoda.
        /// </summary>
        /// <param name="bound">Souřadnice prostoru, do něhož se má provést zarovnání objektu</param>
        /// <param name="size">Velikost objektu, který se má umístit</param>
        /// <param name="alignment">Druh zarovnání objektu do přiděleného prostoru</param>
        /// <param name="sizeMode">Druh práce s velikostí objektu (možnost změny: zvětšení, zmenšení, zachování ratio), vhodné pro obrázky.</param>
        /// <param name="noClipResultToBound">Požadavek, aby výsledný prostor nebyl oříznut do přidělených souřadnic (pokud by objekt byl větší).
        /// false = oříznout (default) /  true = neořezávat</param>
        /// <returns></returns>
        private RectangleF _GetBoundOfSizeAlignedToBound(RectangleF bound, SizeF size, ContentAlignment alignment, AlignSizeMode sizeMode, bool noClipResultToBound)
        {
            RectangleF result = RectangleF.Empty;
            SizeF shift;
            float ratio;
            
            // Podle režimu přizpůsobení velikosti:
            switch (sizeMode)
            {
                case AlignSizeMode.OriginalSize:
                    // Neměnit velikost:
                    shift = GetShiftForAlignment(bound, size, alignment);
                    result = new RectangleF(bound.Location + shift, size);
                    break;
                case AlignSizeMode.Reduce:
                    // V případě potřeby zmenšit a zachovat poměr stran, ale nezvětšovat:
                case AlignSizeMode.Zoom:
                    // Zvětšit nebo zmenšit, ale zachovat poměr stran:
                    ratio = GetRatio(size, bound.Size);
                    if (ratio > 1f && sizeMode == AlignSizeMode.Reduce)
                        ratio = 1f;
                    if (ratio == 1f)
                    {
                        shift = GetShiftForAlignment(bound, size, alignment);
                        result = new RectangleF(bound.Location + shift, size);
                    }
                    else
                    {
                        size = new SizeF(size.Width * ratio, size.Height * ratio);
                        shift = GetShiftForAlignment(bound, size, alignment);
                        result = new RectangleF(bound.Location + shift, size);
                    }
                    break;
                case AlignSizeMode.Fill:
                    result = bound;
                    break;
            }
            if (!noClipResultToBound)
                result.Intersect(bound);
            return result;
        }
        /// <summary>
        /// Vrátí vypočtenou relativní vzdálenost optimálního počátku prostoru o velikosti (size) od počátku prostoru bound,
        /// pokud má být vložen do souřadnic (bound) a zarovnán dle (alignment).
        /// Vrací SizeF, což reprezentuje 
        /// </summary>
        /// <param name="bound"></param>
        /// <param name="size"></param>
        /// <param name="alignment"></param>
        /// <returns></returns>
        protected SizeF GetShiftForAlignment(RectangleF bound, SizeF size, ContentAlignment alignment)
        {
            // Rozdíl velikostí Width a Height:
            float dw = bound.Width - size.Width;
            float dh = bound.Height - size.Height;

            // Přídavek v ose X a Y, aby prostor velikosti Size byl umístěn v rámci bound v daném Alignment:
            float ax = 0f;
            float ay = 0f;
            if (alignment == ContentAlignment.TopCenter || alignment == ContentAlignment.MiddleCenter || alignment == ContentAlignment.BottomCenter)
                ax = dw / 2f;
            else if (alignment == ContentAlignment.TopRight || alignment == ContentAlignment.MiddleRight || alignment == ContentAlignment.BottomRight)
                ax = dw;

            if (alignment == ContentAlignment.MiddleLeft || alignment == ContentAlignment.MiddleCenter || alignment == ContentAlignment.MiddleRight)
                ay = dh / 2f;
            else if (alignment == ContentAlignment.BottomLeft || alignment == ContentAlignment.BottomCenter || alignment == ContentAlignment.BottomRight)
                ay = dh;

            return new SizeF(ax, ay);
        }
        /// <summary>
        /// Vypočítá poměr, v kterém je třeba danou velikost sizeObject zvětšit (ratio větší než 1) nebo zmenšit (ratio menší než 1),
        /// aby vyplnila daný prostor sizeBound zevnitř.
        /// </summary>
        /// <param name="sizeObject"></param>
        /// <param name="sizeBound"></param>
        /// <returns></returns>
        protected float GetRatio(SizeF sizeObject, SizeF sizeBound)
        {
            if (sizeObject.Width <= 0f || sizeObject.Height <= 0f) return 0f;
            float rx = sizeBound.Width / sizeObject.Width;
            float ry = sizeBound.Height / sizeObject.Height;
            return (rx < ry ? rx : ry);
        }
        #endregion
        #region Serializace
        /// <summary>
        /// Zajistí serializaci všech svých hodnot do předaného XML elementu.
        /// Element vytváří nadřízená vrstva (ReportDocument), úkolem komponenty je uložit do XML elementu všechny své hodnoty.
        /// Každá třída ukládá své hodnoty, před tím volá base.XmlSerializeTo(node), aby i předkové uložili svoje data.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="extendedAttributes">Ukládat i rozšířené atributy (true = pro Copy + Paste, false = pro Save a Load)</param>
        protected virtual void XmlSerializeTo(XElement node, bool extendedAttributes)
        { }
        /// <summary>
        /// Načte do sebe veškerá svoje data z XML nodu.
        /// </summary>
        /// <param name="node">XML element</param>
        protected virtual void XmlFillFrom(XElement node)
        { }
        #endregion
        #region Class factory
        /// <summary>
        /// Obsahuje (vždy najde a vrátí) souhrn "vzorových" instancí objektů IReportObject, které jsou v danou chvíli dostupné v systému.
        /// Jde o objekty, které mohou být vkládány do reportů.
        /// Jednotlivé instance jsou vytvořeny bez vztahu na komponentu a dokument, využívají se pouze jejich property IMenuItem.
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public static IEnumerable<IReportObject> ReportObjects
        {
            get
            {
                List<IReportObject> list = new List<IReportObject>(Assistant.GetServiceObjectList<IReportObject>(true));
                return list;
            }
        }
        /// <summary>
        /// Vrátí textovou reprezentaci objektu daného typu, ta se používá pro serializaci (do XML atributu {component Type="..Name.." .. }.
        /// Reverzní metoda GetObject(string name) musí vrátit novou instanci podle typu uvedeného v parametru (název je vytvořen právě nyní).
        /// </summary>
        /// <param name="reportObject"></param>
        /// <returns></returns>
        public static object GetTypeName(IReportObject reportObject)
        {
            if (reportObject == null) return "";
            Type reportType = reportObject.GetType();

            string assembly = "";
            if (!String.Equals(reportType.Assembly.FullName, System.Reflection.Assembly.GetExecutingAssembly().FullName, StringComparison.InvariantCultureIgnoreCase))
                assembly = System.IO.Path.GetFileName(reportType.Assembly.FullName) + ":";

            string nameSpace = "";
            if (assembly.Length > 0 || !String.Equals(reportType.Namespace, typeof(ReportObject).Namespace, StringComparison.InvariantCultureIgnoreCase))
                nameSpace = reportType.Namespace + ".";

            return assembly + nameSpace + reportType.Name;
        }
        /// <summary>
        /// Vytvoří nový objekt daného typu a vrátí jej jako IReportObject.
        /// Název typu vytvořila metoda GetTypeName().
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public static IReportObject GetObject(string name)
        {
            if (String.IsNullOrEmpty(name)) return null;

            Type reportType = null;
            string[] items = name.Split(':');              // Pokud name obsahuje : pak před ní je assembly file, a za ní je namespace.name
            string typeName;
            if (items.Length == 1)
            {   // Lokální assembly
                typeName = items[0];
                if (!typeName.Contains("."))
                    typeName = typeof(ReportObject).Namespace + "." + typeName;
                reportType = typeof(ReportObject).Assembly.GetTypes().FirstOrDefault(t => t.Namespace + "." + t.Name == typeName);
            }
            else
            {   // Externí assembly
                string assemblyFile = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(Application.ExecutablePath), items[0]);
                if (!System.IO.File.Exists(assemblyFile)) return null;
                System.Reflection.Assembly assembly = System.Reflection.Assembly.LoadFile(items[0]);
                typeName = items[1];
                reportType = assembly.GetTypes().FirstOrDefault(t => t.Namespace + "." + t.Name == typeName);
            }

            if (reportType == null) return null;

            IReportObject target = (System.Activator.CreateInstance(reportType) as IReportObject);
            if (target == null) return null;

            return target;
        }
        /// <summary>
        /// Vytvoří nový objekt daného typu a vrátí jej jako IReportObject.
        /// </summary>
        /// <param name="reportType"></param>
        /// <returns></returns>
        public static IReportObject GetObject(Type reportType)
        {
            if (reportType == null) return null;

            IReportObject target = (System.Activator.CreateInstance(reportType) as IReportObject);
            if (target == null) return null;

            return target;
        }
        #endregion
        #region Implementace interface IMenuItem, IReportObject members, předání řízení do protected virtual members
        // IMenuItem
        MenuItemInfo IMenuItem.MenuInfo { get { return this.MenuInfo; } }

        // Property:
        Data.ReportComponent IReportObject.Owner { get { return this.Owner; } set { this.Owner = value; } }
        string IReportObject.ComponentName { get { return this.ComponentName; }  }
        bool IReportObject.EnableMultiBand { get { return this.EnableMultiBand; } }
        EditItemInteractivityMode IReportObject.InteractivityMode { get { return this.InteractivityMode; } }
        RectangleF IReportObject.EditorVisualBounds { get { return this.EditorVisualBounds; } set { this.EditorVisualBounds = value; } }
        bool IReportObject.EditorLocked { get { return this.EditorLocked; } set { this.EditorLocked = value; } }

        // Metody:
        void IReportObject.EditorLogicalBoundsChange(ReportObjectLogicalBoundsChangeArgs args) { this.EditorLogicalBoundsChange(args); }
        void IReportObject.EditorPrepareInteractiveSegments(ReportObjectPrepareSegmentsArgs args) { this.PrepareInteractiveSegments(args); }
        void IReportObject.EditorSegmentInteractivity(ReportObjectInteractiveSegmentsArgs args) { this.EditorSegmentInteractivity(args); }
        void IReportObject.EditorPaint(ReportObjectDrawArgs args) { this.EditorPaint(args); }
        void IReportObject.XmlSerializeTo(XElement node, bool extendedAttributes) { this.XmlSerializeTo(node, extendedAttributes); }
        void IReportObject.XmlFillFrom(XElement node) { this.XmlFillFrom(node); }

        // IPlugin:
        PluginActivityMode IPlugin.PluginActivity { get { return this.PluginActivity; } }
        string IPlugin.LicenseCode { get { return this.LicenseCode; } }

        #endregion
    }
    #endregion
    #region enum ShapeType
    /// <summary>
    /// Druh tvaru
    /// </summary>
    public enum ShapeType
    {
        /// <summary>Čtyřúhelník</summary>
        Rectangle,
        /// <summary>Pouze rohové značky</summary>
        Corners,
        /// <summary>Elipsa</summary>
        Ellipse,
        /// <summary>Kulaté hrany</summary>
        RoundEdge,
        /// <summary>Zkosené hrany</summary>
        BevelEdge
    }
    #endregion
    #region class ReportObjectLine : prvek reportu typu Line
    /// <summary>
    /// ReportObjectLine : prvek reportu typu Line
    /// </summary>
    public class ReportObjectLine : ReportObject
    {
        #region Konstrukce
        /// <summary>
        /// Konstruktor
        /// </summary>
        public ReportObjectLine()
        {
            this.BorderColor = Color.Black;
            this.BorderWidth = 0.5f;
            this.EnableMultiBand = true;
        }
        #endregion
        #region Vlastnosti v Menu + Toolbaru (UI)
        /// <summary>
        /// Property, která obsahuje veškeré informace pro tvorbu UI
        /// </summary>
        protected override MenuItemInfo MenuInfo
        {
            get
            {
                return new MenuItemInfo()
                {
                    Availability = MenuItemAvailability.Users,
                    GroupName = "10",
                    OrderInGroup = 21,
                    Name = "Čáry",
                    TooltipText = "Vloží tvar: čára",
                    ImageSmall = Asol.Reporting.Editor.Pics.IconLibrary22.InsertLine_FromFile,
                    ImageMedium = null
                };
            }
        }
        #endregion
        #region Příprava interaktivních segmentů, testy vlastní interaktivity, háček interaktivity
        /// <summary>
        /// Voláno v době editace.
        /// Připraví a do argumentu args vloží soupis svých segmentů, které chce v dané chvíli zobrazit.
        /// V argumentu dostává informace o prostoru prvku a jeho stavu, do argumentu přidává jednotlivé segmenty.
        /// </summary>
        /// <param name="args"></param>
        protected override void PrepareInteractiveSegments(ReportObjectPrepareSegmentsArgs args)
        {
            args.PrepareInteractiveSegmentsOne(this, 0, true,
                new SheetF(this.Point1.CreateRectangleFromCenter(4f, 4f)),
                this.Point1,
                this.Point1.CreateRectangleFromCenter(4f, 4f),
                SysCursorType.Default, SysCursorType.Default, SysCursorType.NoMoveAuto,
                EditorItemSegmentGripType.UserDefined,
                true, true, false, true, false,
                EditMouseChangeType.OnChange);

            args.PrepareInteractiveSegmentsOne(this, 0, true,
                new SheetF(this.Point2.CreateRectangleFromCenter(4f, 4f)),
                this.Point2,
                this.Point2.CreateRectangleFromCenter(4f, 4f),
                SysCursorType.Default, SysCursorType.Default, SysCursorType.NoMoveAuto,
                EditorItemSegmentGripType.UserDefined,
                true, true, false, true, false,
                EditMouseChangeType.OnChange);
        }
        #endregion
        #region Public property, definující vlastnosti prvku
        /// <summary>
        /// Šířka čáry okrajů (v milimetrech)
        /// </summary>
        [Browsable(true)]
        [Category("Appearance")]
        [Description("Šířka čáry okrajů (v milimetrech)")]
        [DisplayName("Šířka čáry")]
        public float BorderWidth { get; set; }
        /// <summary>
        /// Barva okrajů
        /// </summary>
        [Browsable(true)]
        [Category("Appearance")]
        [Description("Barva okrajů")]
        [DisplayName("Barva okrajů")]
        public Color BorderColor { get; set; }
        /// <summary>
        /// Bod 1
        /// </summary>
        [Browsable(true)]
        public PointF Point1 { get; set; }
        /// <summary>
        /// Bod 2
        /// </summary>
        [Browsable(true)]
        public PointF Point2 { get; set; }
        #endregion
        #region Vykreslení v editoru, SizeChange
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslí Background.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorPaintBackground(ReportObjectDrawArgs args)
        { /* Background se u Line nekreslí */ }
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslí tenký rám okolo prvku.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorPaintFrame(ReportObjectDrawArgs args)
        { /* Frame se u Line nekreslí */ }
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslení obsahu.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorPaintContent(ReportObjectDrawArgs args)
        {
            var state = args.Graphics.Save();
            try
            {
                args.Graphics.SmoothingMode = SmoothingMode.HighQuality;

                using (Pen pen = this.EditorGetPen(args, this.BorderColor, this.BorderWidth))
                {
                    if (pen != null)
                    {
                        args.Graphics.DrawLine(pen, this.Point1, this.Point2);
                    }
                }
            }
            finally
            {
                args.Graphics.Restore(state);
            }
        }
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslení Selectu.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorPaintSelect(ReportObjectDrawArgs args)
        { /* Select se u Line nekreslí */ }
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslení segmentů.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorPaintSegments(ReportObjectDrawArgs args)
        {
            base.EditorPaintSegments(args);
        }
        /// <summary>
        /// Voláno v době editace.
        /// Umožní prvku, aby korigoval souřadnice a/nebo velikost prvku.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorLogicalBoundsChange(ReportObjectLogicalBoundsChangeArgs args)
        {
            switch (args.ChangeType)
            {
                case LogicalBoundsChangeType.Insert:
                    // Vkládání nového objektu: bod počátku lze ignorovat, zde nastavíme optimální úvodní logickou velikost (v milimetrech):
                    args.LogicalBounds = new RectangleF(0, 0, 40f, 0f);
                    break;
            }
        }
        #endregion
        #region Serializace
        /// <summary>
        /// Zajistí serializaci všech svých hodnot do předaného XML elementu.
        /// Element vytváří nadřízená vrstva (ReportDokument), úkolem komponenty je uložit do XML elementu všechny své hodnoty.
        /// Každá třída ukládá své hodnoty, před tím volá base.XmlSerializeTo(node), aby předkové uložili svoje data.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="extendedAttributes">Ukládat i rozšířené atributy (true = pro Copy + Paste, false = pro Save a Load)</param>
        protected override void XmlSerializeTo(XElement node, bool extendedAttributes)
        {
            base.XmlSerializeTo(node, extendedAttributes);
            node.SetAttributeValue("BorderColor", Convertor.ColorToString(this.BorderColor));
            node.SetAttributeValue("BorderWidth", Convertor.SingleToString(this.BorderWidth));
        }
        /// <summary>
        /// Načte do sebe veškerá data z XML nodu.
        /// Volitelně přepíše i svoje vlastní ID (pokud je overrideId = true). To se používá při čtení z XML dokumentu (Load, Revert, Undo, Redo).
        /// V případě Cut/Copy + Paste se overrideId předává false = vzniká nový téměř identický objekt k objektu původnímu, ale s novým ID.
        /// </summary>
        /// <param name="node">XML element</param>
        protected override void XmlFillFrom(XElement node)
        {
            base.XmlFillFrom(node);
            this.BorderColor = (Color)Convertor.StringToColor(ReportDocument.XmlGetXAttributeValue(node, "BorderColor"));
            this.BorderWidth = (Single)Convertor.StringToSingle(ReportDocument.XmlGetXAttributeValue(node, "BorderWidth"));
        }
        #endregion
    }
    #endregion
    #region class ReportObjectShape : prvek reportu typu Rectangle / Ellipse
    /// <summary>
    /// ReportObjectShape : prvek reportu typu Rectangle / Ellipse
    /// </summary>
    public class ReportObjectShape : ReportObject
    {
        #region Konstrukce
        /// <summary>
        /// Konstruktor
        /// </summary>
        public ReportObjectShape()
        {
            this.BorderColor = Color.Black;
            this.BorderWidth = 0.5f;
            this.BackColor = Color.Transparent;
            this.EnableMultiBand = true;
            this.Shape = ShapeType.Rectangle;
            this.ShapeEdge = 0f;
        }
        #endregion
        #region Vlastnosti v Menu + Toolbaru (UI)
        /// <summary>
        /// Property, která obsahuje veškeré informace pro tvorbu UI
        /// </summary>
        protected override MenuItemInfo MenuInfo
        {
            get
            {
                return new MenuItemInfo()
                {
                    Availability = MenuItemAvailability.Users,
                    GroupName = "10",
                    OrderInGroup = 22,
                    Name = "Obdélníky, elipsy",
                    TooltipText = "Vloží tvar: obdélník, rámeček, elipsa",
                    ImageSmall = Asol.Reporting.Editor.Pics.IconLibrary22.InsertShape_FromFile,
                    ImageMedium = null
                };
            }
        }
        #endregion
        #region Public property, definující vlastnosti prvku
        /// <summary>
        /// Šířka čáry okrajů (v milimetrech)
        /// </summary>
        [Browsable(true)]
        [Category("Appearance")]
        [Description("Šířka čáry okrajů (v milimetrech)")]
        [DisplayName("Šířka čáry")]
        public float BorderWidth { get; set; }
        /// <summary>
        /// Barva okrajů
        /// </summary>
        [Browsable(true)]
        [Category("Appearance")]
        [Description("Barva okrajů")]
        [DisplayName("Barva okrajů")]
        public Color BorderColor { get; set; }
        /// <summary>Barva pozadí</summary>
        [Browsable(true)]
        [Category("Appearance")]
        [DisplayName("Barva pozadí")]
        public Color BackColor { get; set; }
        /// <summary>Druh tvaru</summary>
        [Browsable(true)]
        [Category("Appearance")]
        [Description("Druh tvaru")]
        [DisplayName("Tvar")]
        public ShapeType Shape { get; set; }
        /// <summary>Míra zkosení v milimetrech.</summary>
        [Browsable(true)]
        [Category("Appearance")]
        [Description("Míra zkosení v milimetrech")]
        [DisplayName("Míra zkosení")]
        public float ShapeEdge { get; set; }
        #endregion
        #region Vykreslení v editoru, SizeChange
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslení obsahu.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorPaintContent(ReportObjectDrawArgs args)
        {
            var state = args.Graphics.Save();
            try
            {
                args.Graphics.SmoothingMode = SmoothingMode.HighQuality;

                using (Brush brush = this.EditorGetBackBrush(args, this.BackColor, RenderStyle.FlatStyle, 35))
                {
                    if (brush != null)
                    {
                        GraphicsPath path = this.CreateEditorGraphicsPath(args, args.CurrentVisualBound, this.Shape, this.BorderWidth, this.ShapeEdge, GraphicPathType.Background);
                        args.Graphics.FillPath(brush, path);
                    }
                }

                using (Pen pen = this.EditorGetPen(args, this.BorderColor, this.BorderWidth))
                {
                    if (pen != null)
                    {
                        GraphicsPath path = this.CreateEditorGraphicsPath(args, args.CurrentVisualBound, this.Shape, this.BorderWidth, this.ShapeEdge, GraphicPathType.Pen);
                        args.Graphics.DrawPath(pen, path);
                    }
                }
            }
            finally
            {
                args.Graphics.Restore(state);
            }
        }
        /// <summary>
        /// Voláno v době editace.
        /// Umožní prvku, aby korigoval souřadnice a/nebo velikost prvku.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorLogicalBoundsChange(ReportObjectLogicalBoundsChangeArgs args)
        {
            switch (args.ChangeType)
            {
                case LogicalBoundsChangeType.Insert:
                    // Vkládání nového objektu: bod počátku lze ignorovat, zde nastavíme optimální úvodní logickou velikost (v milimetrech):
                    args.LogicalBounds = new RectangleF(0, 0, 40f, 20f);
                    break;
            }
        }
        #endregion
        #region Serializace
        /// <summary>
        /// Zajistí serializaci všech svých hodnot do předaného XML elementu.
        /// Element vytváří nadřízená vrstva (ReportDokument), úkolem komponenty je uložit do XML elementu všechny své hodnoty.
        /// Každá třída ukládá své hodnoty, před tím volá base.XmlSerializeTo(node), aby předkové uložili svoje data.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="extendedAttributes">Ukládat i rozšířené atributy (true = pro Copy + Paste, false = pro Save a Load)</param>
        protected override void XmlSerializeTo(XElement node, bool extendedAttributes)
        {
            base.XmlSerializeTo(node, extendedAttributes);
            node.SetAttributeValue("BorderColor", Convertor.ColorToString(this.BorderColor));
            node.SetAttributeValue("BorderWidth", Convertor.SingleToString(this.BorderWidth));
            node.SetAttributeValue("BackColor", Convertor.ColorToString(this.BackColor));
            node.SetAttributeValue("Shape", Convertor.EnumToString(this.Shape));
            node.SetAttributeValue("ShapeEdge", Convertor.SingleToString(this.ShapeEdge));
        }
        /// <summary>
        /// Načte do sebe veškerá data z XML nodu.
        /// Volitelně přepíše i svoje vlastní ID (pokud je overrideId = true). To se používá při čtení z XML dokumentu (Load, Revert, Undo, Redo).
        /// V případě Cut/Copy + Paste se overrideId předává false = vzniká nový téměř identický objekt k objektu původnímu, ale s novým ID.
        /// </summary>
        /// <param name="node">XML element</param>
        protected override void XmlFillFrom(XElement node)
        {
            base.XmlFillFrom(node);
            this.BorderColor = (Color)Convertor.StringToColor(ReportDocument.XmlGetXAttributeValue(node, "BorderColor"));
            this.BorderWidth = (Single)Convertor.StringToSingle(ReportDocument.XmlGetXAttributeValue(node, "BorderWidth"));
            this.BackColor = (Color)Convertor.StringToColor(ReportDocument.XmlGetXAttributeValue(node, "BackColor"));
            this.Shape = (ShapeType)Convertor.StringToEnum(ReportDocument.XmlGetXAttributeValue(node, "Shape"), ShapeType.Rectangle);
            this.ShapeEdge = (Single)Convertor.StringToSingle(ReportDocument.XmlGetXAttributeValue(node, "ShapeEdge"));
        }
        #endregion
    }
    #endregion
    #region class ReportObjectImage : prvek reportu typu Image
    /// <summary>
    /// ReportObjectImage : prvek reportu typu Image
    /// </summary>
    public class ReportObjectImage : ReportObject, IPropertyDataSource
    {
        #region Konstrukce
        /// <summary>
        /// Konstruktor
        /// </summary>
        public ReportObjectImage()
        {
            this.FileName = "";
            this.SizeMode = AlignSizeMode.Zoom;
            this.Alignement = ContentAlignment.MiddleCenter;
        }
        #endregion
        #region Vlastnosti v Menu + Toolbaru (UI)
        /// <summary>
        /// Property, která obsahuje veškeré informace pro tvorbu UI
        /// </summary>
        protected override MenuItemInfo MenuInfo
        {
            get
            {
                return new MenuItemInfo()
                {
                    Availability = MenuItemAvailability.Users,
                    GroupName = "10",
                    OrderInGroup = 26,
                    Name = "Obrázek",
                    TooltipText = "Vloží obrázek: ze souboru, z databáze",
                    ImageSmall = Asol.Reporting.Editor.Pics.IconLibrary22.InsertImage_FromFile,
                    ImageMedium = null
                };
            }
        }
        #endregion
        #region Public property, definující vlastnosti prvku
        /// <summary>
        /// Název souboru obrázku
        /// </summary>
        [Browsable(true)]
        [Category("Appearance")]
        [Description("Název souboru obrázku")]
        [DisplayName("Ze souboru")]
        [Editor(typeof(PropertyEditorGetFile), typeof(System.Drawing.Design.UITypeEditor))]
        public string FileName { get; set; }
        /// <summary>
        /// Přizpůsobení velikosti obrázku do přiděleného prostoru
        /// </summary>
        [Browsable(true)]
        [Category("Appearance")]
        [Description("Přizpůsobení velikosti obrázku do přiděleného prostoru")]
        [DisplayName("Velikost")]
        public AlignSizeMode SizeMode { get; set; }
        /// <summary>
        /// Zarovnání obrázku
        /// </summary>
        [Browsable(true)]
        [Category("Appearance")]
        [Description("Zarovnání obrázku v jeho prostoru")]
        [DisplayName("Zarovnání")]
        [Editor("System.Drawing.Design.ContentAlignmentEditor", typeof(UITypeEditor))]
        public ContentAlignment Alignement { get; set; }
        #endregion
        #region Vykreslení v editoru, SizeChange
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslení obsahu.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorPaintContent(ReportObjectDrawArgs args)
        {
            Image image = this._EditorGetImage();
            if (image != null)
            {
                ContentAlignment alignment = (this._EditorImageCorrect ? this.Alignement : ContentAlignment.TopLeft);
                AlignSizeMode sizeMode = (this._EditorImageCorrect ? this.SizeMode : AlignSizeMode.Reduce);
                RectangleF area = this.GetBoundOfSizeAlignedToBound(args.CurrentVisualBound, image.Size, alignment, sizeMode);
                if (sizeMode == AlignSizeMode.OriginalSize)
                    args.Graphics.DrawImageUnscaledAndClipped(image, Rectangle.Truncate(area));
                else
                    args.Graphics.DrawImage(image, area);
            }
        }
        /// <summary>
        /// Voláno v době editace.
        /// Umožní prvku, aby korigoval souřadnice a/nebo velikost prvku.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorLogicalBoundsChange(ReportObjectLogicalBoundsChangeArgs args)
        {
            switch (args.ChangeType)
            {
                case LogicalBoundsChangeType.Insert:
                    // Vkládání nového objektu: bod počátku lze ignorovat, zde nastavíme optimální úvodní logickou velikost (v milimetrech):
                    args.LogicalBounds = new RectangleF(0, 0, 40f, 30f);
                    break;
            }
        }
        /// <summary>
        /// Najde a vrátí obrázek pro editor
        /// </summary>
        /// <returns></returns>
        private Image _EditorGetImage()
        {
            string fileName = this.FileName;
            if (String.IsNullOrEmpty(fileName))
                return IconLibrary48.ImageField;

            if (this._EditorImageCache != null && String.Equals(fileName, this._EditorImageCacheName))
            {
                return this._EditorImageCache;
            }
            if (System.IO.File.Exists(fileName))
            {
                try
                {
                    this._EditorImageCache = Image.FromFile(fileName);
                    this._EditorImageCorrect = true;
                }
                catch (Exception)
                {
                    this._EditorImageCache = IconLibrary48.ImageFieldInfo;
                    this._EditorImageCorrect = false;
                }
            }
            else
            {
                this._EditorImageCache = IconLibrary48.ImageFieldRemove;
                this._EditorImageCorrect = false;
            }

            this._EditorImageCacheName = fileName;
            return this._EditorImageCache;
        }
        private string _EditorImageCacheName;
        private Image _EditorImageCache;
        private bool _EditorImageCorrect;
        #endregion
        #region Podpora editace v PropertyGridu: member of interface IPropertyDataSource
        /// <summary>
        /// Metoda, která v konkrétní instanci najde a vrátí seznam dostupných hodnot pro danou property.
        /// </summary>
        /// <param name="propertyDesc">Informace o property, která se právě edituje.</param>
        /// <param name="dataName">Název údaje, který potřebuje editor zjistit</param>
        /// <returns>Vrací zjištěnou hodnotu</returns>
        object IPropertyDataSource.GetPropertyData(PropertyDescriptor propertyDesc, string dataName)
        {
            switch (propertyDesc.Name)
            {
                case "FileName":
                    return this.GetPropertyDataFileName(dataName);
            }
            return null;
        }
        /// <summary>
        /// Vrátí požadovanou hodnotu do PropertyGridu pro položku "FileName"
        /// </summary>
        /// <param name="dataName"></param>
        /// <returns></returns>
        private object GetPropertyDataFileName(string dataName)
        {
            switch (dataName)
            {
                case PropertyEditorGetFile.GET_FILTER:
                    return "Images|*.png;*.jp*g;*.bmp;*.gif|All files (*.*)|*.*";
            }
            return null;
        }
        #endregion
        #region Serializace
        /// <summary>
        /// Zajistí serializaci všech svých hodnot do předaného XML elementu.
        /// Element vytváří nadřízená vrstva (ReportDokument), úkolem komponenty je uložit do XML elementu všechny své hodnoty.
        /// Každá třída ukládá své hodnoty, před tím volá base.XmlSerializeTo(node), aby předkové uložili svoje data.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="extendedAttributes">Ukládat i rozšířené atributy (true = pro Copy + Paste, false = pro Save a Load)</param>
        protected override void XmlSerializeTo(XElement node, bool extendedAttributes)
        {
            base.XmlSerializeTo(node, extendedAttributes);
            node.SetAttributeValue("FileName", Convertor.StringToString(this.FileName));
            node.SetAttributeValue("SizeMode", Convertor.EnumToString<AlignSizeMode>(this.SizeMode));
            node.SetAttributeValue("Alignement", Convertor.EnumToString<ContentAlignment>(this.Alignement));
        }
        /// <summary>
        /// Načte do sebe veškerá data z XML nodu.
        /// Volitelně přepíše i svoje vlastní ID (pokud je overrideId = true). To se používá při čtení z XML dokumentu (Load, Revert, Undo, Redo).
        /// V případě Cut/Copy + Paste se overrideId předává false = vzniká nový téměř identický objekt k objektu původnímu, ale s novým ID.
        /// </summary>
        /// <param name="node">XML element</param>
        protected override void XmlFillFrom(XElement node)
        {
            base.XmlFillFrom(node);
            this.FileName = (string)Convertor.StringToString(ReportDocument.XmlGetXAttributeValue(node, "FileName"));
            this.SizeMode = (AlignSizeMode)Convertor.StringToEnum<AlignSizeMode>(ReportDocument.XmlGetXAttributeValue(node, "SizeMode"), AlignSizeMode.Zoom);
            this.Alignement = (ContentAlignment)Convertor.StringToEnum<ContentAlignment>(ReportDocument.XmlGetXAttributeValue(node, "Alignement"), ContentAlignment.TopLeft);

        }
        #endregion
    }
    /// <summary>
    /// Režim přizpůsobení velikosti Image do přiděleného prostoru
    /// </summary>
    public enum AlignSizeMode
    {
        /// <summary>
        /// Originální velikost
        /// </summary>
        OriginalSize,
        /// <summary>
        /// Zmenšit v případě potřeby, zachovat poměr stran
        /// </summary>
        Reduce,
        /// <summary>
        /// Přizpůsobit velikosti rámečku, zachovat poměr stran
        /// </summary>
        Zoom,
        /// <summary>
        /// Vyplnit rámeček bez ohledu na poměr stran
        /// </summary>
        Fill
    }
    #endregion
    #region abstract class ReportObjectText : bázová třída pro prvky reportu, které zobrazují text (Label, Textbox)
    /// <summary>
    /// ReportObjectText : bázová třída pro prvky reportu, které zobrazují text (Label, Textbox).
    /// Tato třída je abstraktní.
    /// </summary>
    public abstract class ReportObjectText : ReportObject
    {
        #region Konstrukce a proměnné
        /// <summary>
        /// Konstruktor
        /// </summary>
        public ReportObjectText()
        {
            this.BackColor = Color.White;
            this.EditorBackColor = Color.FromArgb(160, 255, 255, 226);       // lehce žlutá
            this.ForeColor = Color.Black;
            this.Alignment = ContentAlignment.TopLeft;
            this.InteractivityMode = EditItemInteractivityMode.StandardActiveResize | EditItemInteractivityMode.AnchorY;
        }
        #endregion
        #region Public property
        /// <summary>
        /// Barva pozadí explicitní
        /// </summary>
        [Category("Appearance")]
        [Description("Barva pozadí explicitní")]
        public Color BackColor { get; set; }
        /// <summary>
        /// Písmo prvku.
        /// Pozor na používání této property: po inicializaci je null, 
        /// ale první get {} zjistí null a dohledá si písmo ve svém parent bandu (this.Owner.OwnerTopBand.DefaultFont).
        /// Toto písmo převezme za své = uloží si jej do sebe a následně jej vrací, dokud nebude do this.Font vloženo něco jiného.
        /// Tedy: změna DefaultFont v OwnerBand už následně (po prvním getu) nezmění this.Font.
        /// (Leda by někdo do this.Font fložil null.)
        /// </summary>
        [Category("Appearance")]
        [Description("Písmo prvku")]
        public Font Font
        {
            get
            {
                if (this._Font != null) return this._Font;
                if (this.Owner != null && this.Owner.OwnerTopBand != null)
                {
                    this._Font = this.Owner.OwnerTopBand.DefaultFont;
                    return this._Font;
                }
                // Pokud někdo chce znát font, a font ještě není určen a není ani určen Owner, tak si musí vystačit s ReportDocument.DefaultReportFont:
                return ReportDocument.DefaultReportFont;
            }
            set { this._Font = value; }
        }
        private Font _Font;
        /// <summary>
        /// Barva písma
        /// </summary>
        [Category("Appearance")]
        [Description("Barva písma")]
        public Color ForeColor { get; set; }
        /// <summary>
        /// Zarovnání obsahu
        /// </summary>
        [Category("Appearance")]
        [Description("Zarovnání obsahu")]
        public ContentAlignment Alignment { get; set; }
        /// <summary>
        /// Barva pozadí v editoru. Použije se pouze v editoru, a pouze když barva BackColor je čistě bílá nebo empty nebo průhledná.
        /// Reálnou barvu pro kreslení pozadí v editoru generuje property CurrentEditorBackColor, ta se používá pro reálné kreslení.
        /// </summary>
        [Browsable(false)]
        public Color EditorBackColor { get; set; }
        /// <summary>
        /// Skutečně aktuálně používaná barva pro vykreslení background v editoru.
        /// Pokud barva this.BackColor je Empty, nebo má složku A = 0, nebo je White, pak se vrátí this.EditorBackColor.
        /// Jinak se vrací this.BackColor
        /// </summary>
        [Browsable(false)]
        public Color CurrentEditorBackColor
        {
            get 
            {
                Color color = this.BackColor;
                if (color.IsEmpty || color.A == 0 || (color.R == 255 && color.G == 255 && color.B == 255))
                    return this.EditorBackColor;
                return color;
            }
        }
        #endregion
        #region Vykreslení textu, SizeChange
        /// <summary>
        /// Voláno při editaci.
        /// Vykreslí daný text podle parametrů.
        /// </summary>
        /// <param name="args"></param>
        /// <param name="text"></param>
        /// <param name="font"></param>
        /// <param name="color"></param>
        /// <param name="alignment"></param>
        /// <param name="multiRows"></param>
        protected void EditorDrawText(ReportObjectDrawArgs args, string text, Font font, Color color, ContentAlignment alignment, bool multiRows)
        {
            SizeF size1 = args.Graphics.MeasureString(text, font);
            SizeF size2 = args.ViewPortConvertor.VisualFromLogical(size1);
            float editorSize = args.ViewPortConvertor.VisualFromLogical(font.Size);
            float coeff = EditorGetTextCoefficient(args);
            editorSize = editorSize / coeff / 1.10f; // font.Size* coeff;
            using (System.Drawing.Font editorFont = new System.Drawing.Font(font.FontFamily.Name, editorSize, font.Style, GraphicsUnit.Point))
            using (Brush brush = new SolidBrush(color))
            {
                SizeF textSize = args.Graphics.MeasureString(text, editorFont);
                SizeF logSize = args.ViewPortConvertor.LogicalFromVisual(textSize);
                RectangleF textArea = GetBoundOfSizeAlignedToBound(args.CurrentVisualBound, textSize, alignment, false);
                StringFormat stringFormat = new StringFormat(StringFormatFlags.LineLimit | StringFormatFlags.NoClip);
                stringFormat.Trimming = StringTrimming.None;
                args.Graphics.DrawString(text, editorFont, brush, textArea, stringFormat);
            }
        }
        /// <summary>
        /// Voláno v době editace.
        /// Umožní prvku, aby korigoval souřadnice a/nebo velikost prvku.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorLogicalBoundsChange(ReportObjectLogicalBoundsChangeArgs args)
        {
            switch (args.ChangeType)
            {
                case LogicalBoundsChangeType.Insert:
                    // Vkládání nového objektu: bod počátku lze ignorovat, zde nastavíme optimální úvodní logickou velikost (v milimetrech):
                    float height = this.Font.GetHeight(96f) * (float)args.ViewPortConvertor.Zoom;
                    SizeF logicalSize = args.ViewPortConvertor.LogicalFromVisual(new SizeF(10f * height, 1.1f * height));
                    args.LogicalBounds = new RectangleF(PointF.Empty, logicalSize);
                    break;
            }
        }
        /// <summary>
        /// Vrátí koeficient, který se použije pro přepočet velikosti písma.
        /// Koeficient je určen z velikosti aktuálně změřeného textu a velikosti očekávané.
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        protected float EditorGetTextCoefficient(ReportObjectDrawArgs args)
        {
            // Provedl jsem sadu měření s daným textem, s různými fonty, a zjistil jsem reálnou velikost textu v milimetrech.
            // Nyní provedu měření textu a porovnám výsledky s očekávanou velikostí, a určím koeficient přepočtu:
            string text = "Hokus Pokusný text, kde měříme jeho velikost. Hokus Pokusný text, kde měříme jeho velikost.";
            float coeff1 = this._EditorGetTextCoefficient(args, text, "Times New Roman", 12, FontStyle.Regular, 160f, 4.8f);
            float coeff2 = this._EditorGetTextCoefficient(args, text, "Times New Roman", 12, FontStyle.Bold, 179f, 4.8f);
            float coeff3 = this._EditorGetTextCoefficient(args, text, "Arial", 12, FontStyle.Regular, 176f, 4.8f);
            float coeff4 = this._EditorGetTextCoefficient(args, text, "Arial", 8, FontStyle.Regular, 118f, 3.2f);
            float coeff5 = this._EditorGetTextCoefficient(args, text, "Arial", 8, FontStyle.Bold, 127f, 3.2f);

            float coeff = (coeff1 + coeff2 + coeff3 + coeff4 + coeff5) / 5f;
            return coeff;
        }
        /// <summary>
        /// Vrátí koeficient přepočtu rozměrů pro daný text, font a očekávanou velikost
        /// </summary>
        /// <param name="args"></param>
        /// <param name="text"></param>
        /// <param name="fontName"></param>
        /// <param name="emSize"></param>
        /// <param name="style"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        private float _EditorGetTextCoefficient(ReportObjectDrawArgs args, string text, string fontName, float emSize, FontStyle style, float width, float height)
        {
            float result = 0f;
            using (Font font = new Font(fontName, emSize, style, GraphicsUnit.Point))
            {
                SizeF textSize = args.Graphics.MeasureString(text, font);
                float coefW = textSize.Width / width;
                float coefH = textSize.Height / height;
                result = (6f * coefW + coefH) / 7f;
            }
            return result;
        }
        #endregion
        #region Serializace
        /// <summary>
        /// Zajistí serializaci všech svých hodnot do předaného XML elementu.
        /// Element vytváří nadřízená vrstva (ReportDokument), úkolem komponenty je uložit do XML elementu všechny své hodnoty.
        /// Každá třída ukládá své hodnoty, před tím volá base.XmlSerializeTo(node), aby předkové uložili svoje data.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="extendedAttributes">Ukládat i rozšířené atributy (true = pro Copy + Paste, false = pro Save a Load)</param>
        protected override void XmlSerializeTo(XElement node, bool extendedAttributes)
        {
            base.XmlSerializeTo(node, extendedAttributes);
            node.SetAttributeValue("BackColor", Convertor.ColorToString(this.BackColor));
            node.SetAttributeValue("Font", Convertor.FontToString(this.Font));
            node.SetAttributeValue("ForeColor", Convertor.ColorToString(this.ForeColor));
            node.SetAttributeValue("Alignment", Convertor.EnumToString(this.Alignment));
        }
        /// <summary>
        /// Načte do sebe veškerá data z XML nodu.
        /// Volitelně přepíše i svoje vlastní ID (pokud je overrideId = true). To se používá při čtení z XML dokumentu (Load, Revert, Undo, Redo).
        /// V případě Cut/Copy + Paste se overrideId předává false = vzniká nový téměř identický objekt k objektu původnímu, ale s novým ID.
        /// </summary>
        /// <param name="node">XML element</param>
        protected override void XmlFillFrom(XElement node)
        {
            base.XmlFillFrom(node);
            this.BackColor = (Color)Convertor.StringToColor(ReportDocument.XmlGetXAttributeValue(node, "BackColor"));
            this.Font = (Font)Convertor.StringToFont(ReportDocument.XmlGetXAttributeValue(node, "Font"));
            this.ForeColor = (Color)Convertor.StringToColor(ReportDocument.XmlGetXAttributeValue(node, "ForeColor"));
            this.Alignment = (ContentAlignment)Convertor.StringToEnum(ReportDocument.XmlGetXAttributeValue(node, "Alignment"), ContentAlignment.TopLeft);
        }
        #endregion
    }
    #endregion
    #region class ReportObjectLabel : třída pro prvek reportu, který zobrazuje Label
    /// <summary>
    /// ReportObjectLabel : třída pro prvek reportu, který zobrazuje Label.
    /// </summary>
    public class ReportObjectLabel : ReportObjectText
    {
        #region Konstrukce
        /// <summary>
        /// Konstruktor
        /// </summary>
        public ReportObjectLabel()
        {
            this.Text = "Label...";
        }
        #endregion
        #region Vlastnosti v Menu + Toolbaru (UI)
        /// <summary>
        /// Property, která obsahuje veškeré informace pro tvorbu UI
        /// </summary>
        protected override MenuItemInfo MenuInfo
        {
            get
            {
                return new MenuItemInfo()
                {
                    Availability = MenuItemAvailability.Users,
                    GroupName = "10",
                    OrderInGroup = 11,
                    Name = "Titulky",
                    TooltipText = "Vloží pevně daný text",
                    ImageSmall = Asol.Reporting.Editor.Pics.IconLibrary22.InsertLabel_FromFile,
                    ImageMedium = null
                };
            }
        }
        #endregion
        #region Public property
        /// <summary>
        /// Zobrazovaný text
        /// </summary>
        [Category("Appearance")]
        [Description("Text")]
        public string Text { get; set; }
        /// <summary>
        /// Text uváděný v nabídce objektů v Combo boxu nad Property gridem
        /// </summary>
        protected override string ComponentName { get { return this.Name + ":  " + this.Text; } }
        #endregion
        #region Vykreslení v editoru
        /// <summary>
        /// Vykreslí obsah v editoru
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorPaintContent(ReportObjectDrawArgs args)
        {
            this.EditorDrawText(args, this.Text, this.Font, this.ForeColor, this.Alignment, true);
        }
        #endregion
        #region Serializace
        /// <summary>
        /// Zajistí serializaci všech svých hodnot do předaného XML elementu.
        /// Element vytváří nadřízená vrstva (ReportDokument), úkolem komponenty je uložit do XML elementu všechny své hodnoty.
        /// Každá třída ukládá své hodnoty, před tím volá base.XmlSerializeTo(node), aby předkové uložili svoje data.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="extendedAttributes">Ukládat i rozšířené atributy (true = pro Copy + Paste, false = pro Save a Load)</param>
        protected override void XmlSerializeTo(XElement node, bool extendedAttributes)
        {
            base.XmlSerializeTo(node, extendedAttributes);
            node.SetAttributeValue("Text", Convertor.StringToString(this.Text));
        }
        /// <summary>
        /// Načte do sebe veškerá data z XML nodu.
        /// Volitelně přepíše i svoje vlastní ID (pokud je overrideId = true). To se používá při čtení z XML dokumentu (Load, Revert, Undo, Redo).
        /// V případě Cut/Copy + Paste se overrideId předává false = vzniká nový téměř identický objekt k objektu původnímu, ale s novým ID.
        /// </summary>
        /// <param name="node">XML element</param>
        protected override void XmlFillFrom(XElement node)
        {
            base.XmlFillFrom(node);
            this.Text = (string)Convertor.StringToString(ReportDocument.XmlGetXAttributeValue(node, "Text"));
        }
        #endregion
    }
    #endregion
    #region class ReportObjectField : třída pro prvek reportu, který zobrazuje políčko s textem
    /// <summary>
    /// ReportObjectField : třída pro prvek reportu, který zobrazuje políčko s textem
    /// </summary>
    public class ReportObjectField : ReportObjectText, IPropertyListSource
    {
        #region Konstrukce
        /// <summary>
        /// Konstruktor
        /// </summary>
        public ReportObjectField()
        {
            this.EditorBackColor = Color.FromArgb(160, 230, 235, 255);   // lehce modrofialová
            this.EditorDefaultText = "value";
        }
        #endregion
        #region Vlastnosti v Menu + Toolbaru (UI)
        /// <summary>
        /// Property, která obsahuje veškeré informace pro tvorbu UI
        /// </summary>
        protected override MenuItemInfo MenuInfo
        {
            get
            {
                return new MenuItemInfo()
                {
                    Availability = MenuItemAvailability.Users,
                    GroupName = "10",
                    OrderInGroup = 16,
                    Name = "Text",
                    TooltipText = "Vloží textové políčko",
                    ImageSmall = Asol.Reporting.Editor.Pics.IconLibrary22.InsertField_FromFile,
                    ImageMedium = null
                };
            }
        }
        #endregion
        #region Public property
        /// <summary>
        /// Zdroj dat
        /// </summary>
        [Category("Data")]
        [DisplayName("Datový zdroj")]
        [Description("Oblast sestavy, z jejichž dat se bude vybírat konkrétní položka")]
        [Editor(typeof(ListBoxEditor), typeof(System.Drawing.Design.UITypeEditor))]
        public string DataSource { get; set; }          // Název property: viz SourceColumn
        /// <summary>
        /// Zdrojový sloupec
        /// </summary>
        [Category("Data")]
        [DisplayName("Položka dat")]
        [Description("Položka = sloupec ze selectu, která se bude v tomto prvku zobrazovat")]
        [Editor(typeof(ListBoxEditor), typeof(System.Drawing.Design.UITypeEditor))]
        public string SourceColumn { get; set; }        // Název property: dávám jej podle abecedy až ZA název DataSource. Důvod: PropertyGrid, když má zobrazen jeden objekt, řadí property podle DisplayName. Ale když má zobrazit více instancí, pak property řadí podle jejich Name.
        /// <summary>
        /// Formátování dat prvku, explicitní
        /// </summary>
        [Category("Data")]
        [DisplayName("Formát")]
        [Description("Formátování dat prvku")]
        public string Format { get; set; }
        /// <summary>
        /// Autosize Height
        /// </summary>
        [Category("Layout")]
        [DisplayName("Autosize Height")]
        public bool AutosizeHeight { get; set; }
        /// <summary>
        /// Zobrazovaný výchozí text
        /// </summary>
        [Browsable(false)]
        protected string EditorDefaultText { get; set; }
        /// <summary>
        /// Text který se zobrazuje při editaci
        /// </summary>
        protected string EditorText
        {
            get
            {
                string sourceColumn = this.SourceColumn;
                if (String.IsNullOrEmpty(sourceColumn))
                    return this.EditorDefaultText;

                string dataSource = this.DataSource;
                string bandSource = null;
                ReportBand ownerBand = this.Owner.OwnerTopBand;
                if (ownerBand != null)
                    bandSource = ownerBand.ReportData.Name;
                if (!String.IsNullOrEmpty(dataSource) && String.Equals(dataSource, bandSource))
                    dataSource = "";
                if (String.IsNullOrEmpty(dataSource))
                    return sourceColumn;

                // return dataSource + "." + sourceColumn;
                return sourceColumn;
            }
        }
        /// <summary>
        /// Text uváděný v nabídce objektů v Combo boxu nad Property gridem
        /// </summary>
        protected override string ComponentName { get { return this.Name + ":  " + this.EditorText; } }
        #endregion
        #region Vykreslení v editoru
        /// <summary>
        /// Vykreslí pozadí v editoru
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorPaintBackground(ReportObjectDrawArgs args)
        {
            UiRenderer.DrawBackground(args.Graphics, args.CurrentVisualBound, this.CurrentEditorBackColor, 20, RenderStyle.FlatStyle, args.MouseState);
        }
        /// <summary>
        /// Vykreslí obsah v editoru
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorPaintContent(ReportObjectDrawArgs args)
        {
            this.EditorDrawText(args, this.EditorText, this.Font, this.ForeColor, this.Alignment, true);
        }
        #endregion
        #region Serializace
        /// <summary>
        /// Zajistí serializaci všech svých hodnot do předaného XML elementu.
        /// Element vytváří nadřízená vrstva (ReportDokument), úkolem komponenty je uložit do XML elementu všechny své hodnoty.
        /// Každá třída ukládá své hodnoty, před tím volá base.XmlSerializeTo(node), aby předkové uložili svoje data.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="extendedAttributes">Ukládat i rozšířené atributy (true = pro Copy + Paste, false = pro Save a Load)</param>
        protected override void XmlSerializeTo(XElement node, bool extendedAttributes)
        {
            base.XmlSerializeTo(node, extendedAttributes);
            node.SetAttributeValue("DataSource", Convertor.StringToString(this.DataSource));
            node.SetAttributeValue("SourceColumn", Convertor.StringToString(this.SourceColumn));
            if (this.AutosizeHeight)
                node.SetAttributeValue("AutosizeHeight", Convertor.BooleanToString(this.AutosizeHeight));
        }
        /// <summary>
        /// Načte do sebe veškerá data z XML nodu.
        /// Volitelně přepíše i svoje vlastní ID (pokud je overrideId = true). To se používá při čtení z XML dokumentu (Load, Revert, Undo, Redo).
        /// V případě Cut/Copy + Paste se overrideId předává false = vzniká nový téměř identický objekt k objektu původnímu, ale s novým ID.
        /// </summary>
        /// <param name="node">XML element</param>
        protected override void XmlFillFrom(XElement node)
        {
            base.XmlFillFrom(node);
            this.DataSource = (string)Convertor.StringToString(ReportDocument.XmlGetXAttributeValue(node, "DataSource"));
            this.SourceColumn = (string)Convertor.StringToString(ReportDocument.XmlGetXAttributeValue(node, "SourceColumn"));
            this.AutosizeHeight = (bool)Convertor.StringToBoolean(ReportDocument.XmlGetXAttributeValue(node, "AutosizeHeight"));
        }
        #endregion
        #region IPropertyListSource Members : tvorba seznamu nabídek do PropertyGridu
        /// <summary>
        /// Metoda, která v aktuální instanci (kde je implementovaná) a pro určenou property (parametr propertyDesc) najde a vrátí soupis položek do nabídky DropDownListu.
        /// </summary>
        /// <param name="propertyDesc">Informace o property, která se právě edituje.</param>
        /// <returns>Vrací seznam položek do nabídky DropDownListu</returns>
        IEnumerable<string> IPropertyListSource.GetPropertyListItems(PropertyDescriptor propertyDesc)
        {
            switch (propertyDesc.Name)
            {
                case "DataSource": return this.Owner.OwnerTopBand.GetAvailableDataTables();
                case "SourceColumn": return this.Owner.OwnerTopBand.GetAvailableDataColumn(this.DataSource);
            }
            return null;
        }
        #endregion
    }
    #endregion
    #region class ReportObjectNested : prvek reportu typu Nested (vnořený report)
    /// <summary>
    /// ReportObjectNested : prvek reportu typu Nested (vnořený report)
    /// </summary>
    public class ReportObjectNested : ReportObject
    {
        #region Konstrukce
        /// <summary>
        /// Konstruktor
        /// </summary>
        public ReportObjectNested()
        {
            this.BorderColor = Color.Black;
            this.BorderWidth = 0.5f;
            this.EnableMultiBand = true;
        }
        #endregion
        #region Vlastnosti v Menu + Toolbaru (UI)
        /// <summary>
        /// Property, která obsahuje veškeré informace pro tvorbu UI
        /// </summary>
        protected override MenuItemInfo MenuInfo
        {
            get
            {
                return new MenuItemInfo()
                {
                    Availability = MenuItemAvailability.Users,
                    GroupName = "10",
                    OrderInGroup = 21,
                    Name = "Čáry",
                    TooltipText = "Vloží tvar: čára",
                    ImageSmall = Asol.Reporting.Editor.Pics.IconLibrary22.InsertLine_FromFile,
                    ImageMedium = null
                };
            }
        }
        #endregion
        #region Příprava interaktivních segmentů, testy vlastní interaktivity, háček interaktivity
        /// <summary>
        /// Voláno v době editace.
        /// Připraví a do argumentu args vloží soupis svých segmentů, které chce v dané chvíli zobrazit.
        /// V argumentu dostává informace o prostoru prvku a jeho stavu, do argumentu přidává jednotlivé segmenty.
        /// </summary>
        /// <param name="args"></param>
        protected override void PrepareInteractiveSegments(ReportObjectPrepareSegmentsArgs args)
        {
            args.PrepareInteractiveSegmentsOne(this, 0, true,
                new SheetF(this.Point1.CreateRectangleFromCenter(4f, 4f)),
                this.Point1,
                this.Point1.CreateRectangleFromCenter(4f, 4f),
                SysCursorType.Default, SysCursorType.Default, SysCursorType.NoMoveAuto,
                EditorItemSegmentGripType.UserDefined,
                true, true, false, true, false,
                EditMouseChangeType.OnChange);

            args.PrepareInteractiveSegmentsOne(this, 0, true,
                new SheetF(this.Point2.CreateRectangleFromCenter(4f, 4f)),
                this.Point2,
                this.Point2.CreateRectangleFromCenter(4f, 4f),
                SysCursorType.Default, SysCursorType.Default, SysCursorType.NoMoveAuto,
                EditorItemSegmentGripType.UserDefined,
                true, true, false, true, false,
                EditMouseChangeType.OnChange);
        }
        #endregion
        #region Public property, definující vlastnosti prvku
        /// <summary>
        /// Šířka čáry okrajů (v milimetrech)
        /// </summary>
        [Browsable(true)]
        [Category("Appearance")]
        [Description("Šířka čáry okrajů (v milimetrech)")]
        [DisplayName("Šířka čáry")]
        public float BorderWidth { get; set; }
        /// <summary>
        /// Barva okrajů
        /// </summary>
        [Browsable(true)]
        [Category("Appearance")]
        [Description("Barva okrajů")]
        [DisplayName("Barva okrajů")]
        public Color BorderColor { get; set; }
        /// <summary>
        /// Bod 1
        /// </summary>
        [Browsable(true)]
        public PointF Point1 { get; set; }
        /// <summary>
        /// Bod 2
        /// </summary>
        [Browsable(true)]
        public PointF Point2 { get; set; }
        #endregion
        #region Vykreslení v editoru, SizeChange
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslí Background.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorPaintBackground(ReportObjectDrawArgs args)
        { /* Background se u Line nekreslí */ }
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslí tenký rám okolo prvku.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorPaintFrame(ReportObjectDrawArgs args)
        { /* Frame se u Line nekreslí */ }
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslení obsahu.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorPaintContent(ReportObjectDrawArgs args)
        {
            var state = args.Graphics.Save();
            try
            {
                args.Graphics.SmoothingMode = SmoothingMode.HighQuality;

                using (Pen pen = this.EditorGetPen(args, this.BorderColor, this.BorderWidth))
                {
                    if (pen != null)
                    {
                        args.Graphics.DrawLine(pen, this.Point1, this.Point2);
                    }
                }
            }
            finally
            {
                args.Graphics.Restore(state);
            }
        }
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslení Selectu.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorPaintSelect(ReportObjectDrawArgs args)
        { /* Select se u Line nekreslí */ }
        /// <summary>
        /// Voláno v době editace.
        /// Vykreslení segmentů.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorPaintSegments(ReportObjectDrawArgs args)
        {
            base.EditorPaintSegments(args);
        }
        /// <summary>
        /// Voláno v době editace.
        /// Umožní prvku, aby korigoval souřadnice a/nebo velikost prvku.
        /// </summary>
        /// <param name="args"></param>
        protected override void EditorLogicalBoundsChange(ReportObjectLogicalBoundsChangeArgs args)
        {
            switch (args.ChangeType)
            {
                case LogicalBoundsChangeType.Insert:
                    // Vkládání nového objektu: bod počátku lze ignorovat, zde nastavíme optimální úvodní logickou velikost (v milimetrech):
                    args.LogicalBounds = new RectangleF(0, 0, 40f, 0f);
                    break;
            }
        }
        #endregion
        #region Serializace
        /// <summary>
        /// Zajistí serializaci všech svých hodnot do předaného XML elementu.
        /// Element vytváří nadřízená vrstva (ReportDokument), úkolem komponenty je uložit do XML elementu všechny své hodnoty.
        /// Každá třída ukládá své hodnoty, před tím volá base.XmlSerializeTo(node), aby předkové uložili svoje data.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="extendedAttributes">Ukládat i rozšířené atributy (true = pro Copy + Paste, false = pro Save a Load)</param>
        protected override void XmlSerializeTo(XElement node, bool extendedAttributes)
        {
            base.XmlSerializeTo(node, extendedAttributes);
            node.SetAttributeValue("BorderColor", Convertor.ColorToString(this.BorderColor));
            node.SetAttributeValue("BorderWidth", Convertor.SingleToString(this.BorderWidth));
        }
        /// <summary>
        /// Načte do sebe veškerá data z XML nodu.
        /// Volitelně přepíše i svoje vlastní ID (pokud je overrideId = true). To se používá při čtení z XML dokumentu (Load, Revert, Undo, Redo).
        /// V případě Cut/Copy + Paste se overrideId předává false = vzniká nový téměř identický objekt k objektu původnímu, ale s novým ID.
        /// </summary>
        /// <param name="node">XML element</param>
        protected override void XmlFillFrom(XElement node)
        {
            base.XmlFillFrom(node);
            this.BorderColor = (Color)Convertor.StringToColor(ReportDocument.XmlGetXAttributeValue(node, "BorderColor"));
            this.BorderWidth = (Single)Convertor.StringToSingle(ReportDocument.XmlGetXAttributeValue(node, "BorderWidth"));
        }
        #endregion
    }
    #endregion
}
